//
//  UIImage_public extension.swift
//  Wanke
//
//  Created by BO ZHOU on 2020/10/18.
//

import UIKit


public extension UIImage {
    
    
    /** 返回一张带有尖角的圆形图片, 默认尖角高度为图形宽高的十分之一, 尖角度数为60度 */
    var arrowRoundImage: UIImage? {
            
        // 箭头高度 (箭头三角形高度)
//        let arrowHeight: CGFloat = min(self.size.width, self.size.height) / 4
        
        // 箭头角度 (底部尖角角度)
        let triAngle: CGFloat = CGFloat.pi / 180 * 80
        
        return arrowRoundImage(with: 1/7, triAngle: triAngle)
    }
    
    
    /**
     * 根据三角箭头高度和箭头角度生成尖角图片
     * - parameter arrowPercent: 箭头高度和总高度的比例, 建议传入高度与 `min(width, height)` 作比
     * - parameter triAngle: 箭头角度
     */
    func arrowRoundImage(with arrowPercent: CGFloat, triAngle: CGFloat) -> UIImage? {
        
        
        let midX = self.size.width / 2
        
        let arrowHeight = min(self.size.width, self.size.height) * arrowPercent
        
        // 左右宽度
        let triWidth = tan(triAngle/2) * arrowHeight
        
        let maxY = self.size.height - arrowHeight
        
        let triangleRightPoint = CGPoint(x: midX + triWidth, y: maxY)
        let triangleLeftPoint = CGPoint(x: midX - triWidth, y: maxY)
        let triangleBottomPoint = CGPoint(x: midX, y: maxY + arrowHeight)
        
        // 注意: 贝塞尔曲线如果不需要使用矩形, 圆的话, 一定不要用addArc, addRect等方法创建, 这几种方法创建的贝塞尔曲线会默认加矩形线或者圆形线
        let path = UIBezierPath()
        
        // 画三角形尖角
        path.move(to: triangleRightPoint)
        path.addLine(to: triangleBottomPoint)
        path.addLine(to: triangleLeftPoint)

        // 圆半径 (已知三角高度, 三角底部的尖角度数, 图片最大高度, 未知: 圆半径r, 和圆心角对应三角部分的度数, 这两个未知数可以列二元二次方程)
        /**
         * 已知: 三角形顶部单边宽度triWidth为 `a`, 三角形高度arrowHeight为 `b`, 图片最大裁剪高度为 `c`
         * 未知: 设圆心角对应三角形的度数的一半为 `α`, 圆半径为 `r`
         *
         * 可列算式:  ① sinα * r = a
         *          ② cosα * r + r + b = c
         *          根据 sinα² + cosα² = 1 可以将 ②变形 --> ③: cosα * r = c - r - b
         *          ①² + ③² ==>  sinα² * r² + cosα² * r² = a² + (c - r - b)²  ==>  r² = a² + ((c - b) - r)² ==> r = (a² + (c - b)²) / (c - b)
         */
        
        let c = arrowHeight / arrowPercent
//        c = self.size.height
        var r = (triWidth*triWidth + (c - arrowHeight) * (c - arrowHeight)) / ((c - arrowHeight) * 2)

        // 圆心到底部三角形的距离
        var r_h = r - (2*r + arrowHeight - c)

        // 圆心坐标
        var arcCenter = CGPoint(x: self.size.width/2, y: self.size.height - arrowHeight - r_h)


        // 圆心角的一半
        var arcAngle = acos(r_h / r)


        if r * 2 > self.size.width {
            print("圆不完整, 调整了")

            // 这里可以将r适配为width/2, 来计算圆心角
            r = self.size.width/2

            arcAngle = asin(triWidth / r)

            r_h = cos(arcAngle) * r

            arcCenter = CGPoint(x: self.size.width/2, y: self.size.height - arrowHeight - r_h)
        }

        // 起始角度
        let startAngle = CGFloat.pi / 2 + arcAngle

        // 结束角度
        let endAngle = CGFloat.pi * 2 + CGFloat.pi / 2 - arcAngle
        
        path.addArc(withCenter: arcCenter, radius: r, startAngle: startAngle, endAngle: endAngle, clockwise: true)
                
        path.close()
        
        /** 开启图形操作上下文 */
        UIGraphicsBeginImageContextWithOptions(self.size, false, 0)
        
        /** 裁剪操作, 必须开启了图形上下文, 否则无效 */
        path.addClip()
        
        let drawHeight = r + r_h + arrowHeight
        
        // 先生成一张大图, 和原self尺寸一致, 因为开启图形上下文的时候的size就是self.size, 所以最终获取的图片size还是self.size, 我们想要的部分正常在size显示, 超出的部分是透明色
        self.draw(in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
        
        let arrowImage = UIGraphicsGetImageFromCurrentImageContext()
        
        UIGraphicsEndImageContext()
        
        // todo: 这里写宽度为  r*2 有问题, 什么时候调研一下
        let frame = CGRect(x: 0, y: self.size.height - drawHeight, width: self.size.width, height: drawHeight)
        
        // 根据上面生成的大图, 按照我们想要的部分精准截取
        let cropImage = arrowImage!.cropping(to: CGRect(x: frame.origin.x * scale, y: frame.origin.y * scale, width: frame.width * scale, height: frame.height * scale))
        
        
        return cropImage
    }
    
    
    
    /**
     * 根据三角箭头高度和箭头角度生成尖角图片
     * - parameter arrowHeight: 箭头高度, 建议传入高度与 `min(width, height)` 作比
     * - parameter triAngle: 箭头角度
     */
    func arrowRoundImage(with radius: CGFloat, arrowPercent: CGFloat, triAngle: CGFloat) -> UIImage? {
        
        
        let midX = self.size.width / 2
        
        let arrowHeight = min(self.size.width, self.size.height) * arrowPercent
        // 左右宽度
        let triWidth = tan(triAngle/2) * arrowHeight
        
        let maxY = self.size.height - arrowHeight
        
        let triangleRightPoint = CGPoint(x: midX + triWidth, y: maxY)
        let triangleLeftPoint = CGPoint(x: midX - triWidth, y: maxY)
        let triangleBottomPoint = CGPoint(x: midX, y: maxY + arrowHeight)
        
        // 注意: 贝塞尔曲线如果不需要使用矩形, 圆的话, 一定不要用addArc, addRect等方法创建, 这几种方法创建的贝塞尔曲线会默认加矩形线或者圆形线
        let path = UIBezierPath()
        
        // 画三角形尖角
        path.move(to: triangleRightPoint)
        path.addLine(to: triangleBottomPoint)
        path.addLine(to: triangleLeftPoint)
        
        // 圆半径 (已知三角高度, 三角底部的尖角度数, 图片最大高度, 未知: 圆半径r, 和圆心角对应三角部分的度数, 这两个未知数可以列二元二次方程)
        /**
         * 已知: 三角形顶部单边宽度triWidth为 `a`, 三角形高度arrowHeight为 `b`, 图片最大裁剪高度为 `c`
         * 未知: 设圆心角对应三角形的度数的一半为 `α`, 圆半径为 `r`
         *
         * 可列算式:  ① sinα * r = a
         *          ② cosα * r + r + b = c
         *          根据 sinα² + cosα² = 1 可以将 ②变形 --> ③: cosα * r = c - r - b
         *          ①² + ③² ==>  sinα² * r² + cosα² * r² = a² + (c - r - b)²  ==>  r² = a² + ((c - b) - r)² ==> r = (a² + (c - b)²) / (c - b)
         */
        var r = (triWidth*triWidth + (self.size.height - arrowHeight) * (self.size.height - arrowHeight)) / ((self.size.height - arrowHeight) * 2)
        
        // 圆心到底部三角形的距离
        var r_h = r - (2*r + arrowHeight - self.size.height)
        
        // 圆心坐标
        var arcCenter = CGPoint(x: self.size.width/2, y: r)
        
        // 圆心角的一半
        var arcAngle = acos(r_h / r)
        
        
        if r * 2 > self.size.width {
            print("圆不完整, 调整了")
            
            // 这里可以将r适配为width/2, 来计算圆心角
            r = self.size.width/2
            
            arcAngle = asin(triWidth / r)
            
            r_h = cos(arcAngle) * r
            
            arcCenter = CGPoint(x: self.size.width/2, y: self.size.height - arrowHeight - r_h)
        }
        
        // 起始角度
        let startAngle = CGFloat.pi / 2 + arcAngle
        
        // 结束角度
        let endAngle = CGFloat.pi * 2 + CGFloat.pi / 2 - arcAngle
        
        path.addArc(withCenter: arcCenter, radius: r, startAngle: startAngle, endAngle: endAngle, clockwise: true)
                
        path.close()
        
        /** 开启图形操作上下文 */
        UIGraphicsBeginImageContextWithOptions(self.size, false, 0)
        
        /** 裁剪操作, 必须开启了图形上下文, 否则无效 */
        path.addClip()
        
        let drawHeight = r + r_h + arrowHeight
        
        // 先生成一张大图, 和原self尺寸一致, 因为开启图形上下文的时候的size就是self.size, 所以最终获取的图片size还是self.size, 我们想要的部分正常在size显示, 超出的部分是透明色
        self.draw(in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
        
        let arrowImage = UIGraphicsGetImageFromCurrentImageContext()
        
        UIGraphicsEndImageContext()
        
        let frame = CGRect(x: 0, y: self.size.height - drawHeight, width: r*2, height: drawHeight)
        
        // 根据上面生成的大图, 按照我们想要的部分精准截取
        let cropImage = arrowImage!.cropping(to: CGRect(x: frame.origin.x * scale, y: frame.origin.y * scale, width: frame.width * scale, height: frame.height * scale))
        
        
        return cropImage
    }
    
    
    ///裁剪image，rect是相对于image.size大小
    func cropping(to rect: CGRect) -> UIImage? {
        guard self.size.width > rect.origin.x else {
            return nil
        }
        guard self.size.height > rect.origin.y else {
            return nil
        }
        let scaleRect = CGRect(x: rect.origin.x*self.scale, y: rect.origin.y*self.scale, width: rect.width*self.scale, height: rect.height*self.scale)
        if let cgImage = self.cgImage?.cropping(to: scaleRect) {
            let cropImage = UIImage(cgImage: cgImage, scale: self.scale, orientation: .up)
            return cropImage
        } else {
            return nil
        }
    }
}
